package repository.implementation;

import static org.jooq.util.maven.example.Routines.insertingredients;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import opennlp.tools.cmdline.postag.POSModelLoader;
import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTaggerME;
import opennlp.tools.tokenize.WhitespaceTokenizer;

import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import org.jooq.util.maven.example.routines.Insertrecipe;

public class DataBaseWorker implements Runnable {
    private final RegistrationRepository repository;
    private final boolean[] needed;
    private final String userName = "postgres";
    private final String password = "postgres";
    private final String url = "jdbc:postgresql:cook-with-granny";
    private final POSTaggerME tagger;
    private static int dbWorkerId = 0;
    private final int localId;

    // see
    // http://blog.dpdearing.com/2011/12/opennlp-part-of-speech-pos-tags-penn-english-treebank/
    private final Set<String> allowedPOS = new HashSet<String>();
    {
        allowedPOS.addAll(Arrays.asList("NNP", "NNS", "NNPS", "NN"));
    }

    public DataBaseWorker(final RegistrationRepository repository, final int numberOfCRWorkers) {
        dbWorkerId++;
        localId = dbWorkerId;
        this.repository = repository;
        needed = new boolean[numberOfCRWorkers];
        Arrays.fill(needed, Boolean.TRUE);
        final POSModel model = new POSModelLoader().load(new File("en-pos-maxent.bin"));
        tagger = new POSTaggerME(model);
    }

    public void StopWorker(final int index) {
        needed[index - 1] = false;
    }

    private boolean readyToStop() {
        for (int i = 0; i < needed.length; i++)
            if (needed[i])
                return false;
        return true;
    }

    @Override
    public void run() {
        Insertrecipe insertRecipe;
        RecipeModel recipeModel = null;
        Connection conn = null;
        DSLContext create = null;

        try {
            conn = DriverManager.getConnection(url, userName, password);
            create = DSL.using(conn, SQLDialect.POSTGRES);
            System.out.println("worker #" + localId + " started working...");
            while (true) {
                if (readyToStop())
                    if (repository.isEmpty())
                        break;

                recipeModel = repository.UnregisterRecipe();
                if (recipeModel.recipeName.equalsIgnoreCase("EXIT"))
                    continue;

                insertRecipe = GetInsertRecipe(recipeModel);
                insertRecipe.execute(create.configuration());
                final int newRecipeId = insertRecipe.getReturnValue();
                for (int i = 0; i < recipeModel.ingredientMetric.size(); i++) {
                    final String name = recipeModel.ingredientName.get(i);
                    final String processedName = processIngredientName(name);

                    // FIXME: remove concatenation
                    insertingredients(create.configuration(), newRecipeId, recipeModel.ingredientMetric.get(i),
                            processedName, recipeModel.ingredientQuantity.get(i));

                }
                System.out.println("system information: new rows inserted! RecipeId = " + newRecipeId);
            }

            System.out.println("DataBase worker #" + localId + " finished working...");
        } catch (final InterruptedException e) {
            e.printStackTrace();
            System.out.println("DataBase worker #" + localId + " finished working unexpectedly...");

        } catch (final SQLException e1) {
            e1.printStackTrace();
            System.out.println("DataBase worker #" + localId + " finished working unexpectedly...");

        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (final SQLException ignore) {
                    ignore.printStackTrace();
                    System.out.println("DataBase worker #" + localId + " finished working unexpectedly...");
                }
            }
        }

    }

    private Insertrecipe GetInsertRecipe(final RecipeModel model) {
        final Insertrecipe result = new Insertrecipe();

        result.setPcontent(model.recipeContent);
        result.setPimageurl(model.recipePicUrl);
        result.setPname(model.recipeName);
        result.setPurl(model.recipeUrl);
        result.setPtime(model.recipeTime);

        return result;
    }

    private String processIngredientName(final String name) {
        final String simpleName = name.trim().replaceAll("\\(.*\\)", "");
        // dirty hack ;)
        if (simpleName.startsWith("pecan")) {
            return simpleName;
        }
        if (simpleName.startsWith("brown sugar")) {
            return "brown sugar";
        }
        if (simpleName.startsWith("olive oil")) {
            return "olive oil";
        }
        final String whitespaceTokenizerLine[] = WhitespaceTokenizer.INSTANCE.tokenize(simpleName);
        final String[] tags = tagger.tag(whitespaceTokenizerLine);
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < tags.length; i++) {
            if (allowedPOS.contains(tags[i])) {
                sb.append(whitespaceTokenizerLine[i]).append(" ");
            }
        }
        return sb.toString().isEmpty() ? simpleName : sb.toString().trim().replace(",", "");
    }
}
